import folding;

/* Implement the N3/RDF functionality for SR programs. 
   Supports triples and quads -- in the form of named graph structures.
 */
 
 #right((!),500);
 #right(($),450);
 
 -- Validation rules for N3 graph expressions
 # graph{} :: expression;
 # graph{?G} :: expression :- G::triples ## {
 
 # #(?A;?B)# :: triples :- A::triples :& B::triples;
 # #(?A;)# :: triples :- A::triples;
 # ?T :: triples :- T::triple;
 
 # ?S ! ?V :: triple :- S::nounPhrase :& V::verbPhrase;
 # ?T :: triple :- error("$T is not a valid triple");
 
 # ?P $ ?O :: verbPhrase :- P::verb :& O::nounPhrase;
 # [ ?VP ] :: verbPhrase :- VP::verbPhrases;
 # ?VP :: verbPhrase :- error("$VP must have at least one predicate and one object");
 
 # ?A,?B :: verbPhrases :- A::verbPhrase :& B::verbPhrases;
 # ?A :: verbPhrases :- A::verbPhrase;
 
 # [?V] :: verb :- V::verbs;
 # ?V :: verb :- V::concept;
 
 # #(?V1,?Vr)# :: verbs :- V1::concept :& Vr::verbs;
 # ?V :: verbs :- V::concept;

 # [ ?NP ] :: nounPhrase :- NP :: nounPhrases;
 # string : string :: nounPhrase;
 # string :: nounPhrase;
 # ?C :: nounPhrase :- C::concept;
 
 # #(?NP1,?NPr)# :: nounPhrases :- NP1::nounPhrase :& NPr::nounPhrases;
 # ?NP :: nounPhrases :- NP::nounPhrase;
 
 -- # identifier @ identifier : identifier :: concept;
 -- # identifier @ identifier :: concept;
 # ( ?P $ ?O ) :: concept :- P::verb :& O::nounPhrase;
 # identifier : identifier :: concept;
 # identifier :: concept;
 # ?C :: concept :- error("$C is not a recognized form of concept");
 };
 -- Implementation 
 
 -- Standard types to support N3 notation
 type n3Graph is alias of relation of fact;
 
 type fact is fact(n3Concept,n3Concept,n3Concept);
 
 type n3Concept is n3C(string,string)
              or n3S(string,string);
              
 -- Macros to convert graph expressions into regular Star structures.
 # graph{} ==> relation{} has type n3Graph;
 # graph{?Graph} ==> relation of { triples(Graph) } ## {

  triples(A) is wrapSemi(mapSemi(triple,A));     

  triple(SoFar,<| ?Sub ! ?VP |>) is SoFar++tripleJoin(trNounPhrase(list of {},Sub),trVerbPhrase(list of {},VP));
 
  trVerbPhrase(SoFar,<| [ ?VPs ] |>) is SoFar++mapComma(trVerbPhrase,VPs); 
  trVerbPhrase(SoFar,<| ?V $ ?O |>) is SoFar++pairJoin(trVerb(list of {},V),trNounPhrase(list of {},O));
  
  trVerb(SoFar,<| [?Vs] |>) is SoFar++mapComma(trVerb,Vs);
  trVerb(SoFar, C) is list of {SoFar..;trConcept(C)};
  
  trNounPhrase(SoFar,<| [ ?NPs ] |>) is SoFar++mapComma(trNounPhrase,NPs);
  trNounPhrase(SoFar, N ) is list of {SoFar..;trConcept(N) };
      
  trConcept(<| #(string?S)# : #(string?Lng)# |>) is <| n3S(?S,?Lng) |>; 
  trConcept(<| #(identifier?G)# : #(identifier ? C)# |>) is <| n3C(?nameString(G), ?nameString(C)) |>;
  trConcept(<| identifier?C |>) is <| n3C("", ?nameString(C)) |>;
  trConcept(<| string ?S |>) is <| n3S(?S,"") |>;
  
  nameString(nameAst(Lc,N)) is stringAst(Lc,N);
  
  unwrapSemi(<| ?L ; ?R |>,Lst) is unwrapSemi(R,unwrapSemi(L,Lst));
  unwrapSemi(El,Lst) is list of {Lst..;El};
 
  wrapSemi(list of {El}) is <| ?El |>;
  wrapSemi(list of {El;..More}) is <| ?El ; ?wrapSemi(More) |>;
 
  mapSemi(F,A) is leftFold(F,list of {},unwrapSemi(A,list of {}));

  unwrapComma(<| ?L , ?R |>,Lst) is unwrapComma(R,unwrapComma(L,Lst));
  unwrapComma(El,Lst) is list of {Lst..;El};

  mapComma(F,A) is leftFold(F,list of {},unwrapComma(A,list of {}));
  
  pairJoin(L1,L2) is list of { (E1,E2) where E1 in L1 and E2 in L2 };
  
  tripleJoin(L1,L2) is list of { <| fact(?S,?V,?O) |> where S in L1 and (V,O) in L2 };
};